/********************************************************
info: 客户端的数据是特定格式的json数据，对其进行解析，分析，以及重处理
data: 2022/02/10
author: hlp
********************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//模拟接收到的json数据，打印最终得数据
void test_get_clientdata();
//解析接收到得json数据，并打印获取到得各个字段 用到了json库得解析
void check_client_data();
//解析收到的json字符串进行解析  打印每个字段的值
//void parse_json_str();

int main()
{
	//构造客户端得数据并打印出来，只是其中一个实例，如果网络传输，考虑一些特殊字符
	test_get_clientdata();
	//我要根据客户端得数据进行解析后，获取到相应得json字符串信息并打印。
	check_client_data();
	//上一步已经正确获取到数据 对获取到的数据进行json解析提取目标各个字段
	//parse_json_str(); //这个接口参考cjson中的测试代码，使用cjson对json字符串进行解析

	//对获取到的数据进行处理  即用http client进行发送 参考 http_client

	return 0;
}

unsigned char vps_checkxor(const char *strData,int len)  
{  
    char checksum = 0;  
    for (int i = 0;i < len;i++)  
    {  
        checksum = checksum ^ strData[i];  
    }  
    return (unsigned char)checksum;  
}

//构造客户端发送得json数据并打印出来
void test_get_clientdata()
{
	// 2|4|119|{"XXX":"12345","XXX1":1178263,"XXXY":2083177,"XXX2":121.7,"XXX3":"AVB","XXX4":1234567}
	const char * client_json_data = "{\"DNIS\":\"dnis\" , \"ACDGroup\":\"ACDGroup\" ,\"TrunkNo\":\"TrunkNo\" ,\"ExtNo\":\"ExtNo\" ,\
\"CallerNo\":\"CallerNo\" ,\"CalledPartyNo\":\"CalledPartyNo\" , \"CallMark\":\"CallMark\" ,\"UniqueCallID\":\"UniqueCallID\" ,\
\"IncidentNo\":\"IncidentNo\" , \"StationOrDepot\":\"StationOrDepot\" ,\"OperatorID\":\"OperatorID\" ,\
\"WorkstationNo\":\"WorkstationNo\" , \"CallerVehicleID\":\"CallerVehicleID\" ,\"GSSI\":\"GSSI\" ,\"GSSI\":\"GSSI\" ,\
\"ResourceStatus\":\"ResourceStatus\" ,\"OicOrOfficerID\":\"OicOrOfficerID\" ,\"ISSI\":\"ISSI\" , \"CalledSSI\":\"CalledSSI\" ,\
\"CallType\":\"CallType\" ,\"FileLink\":\"FileLink\" , \"SenderDeviceID\":\"SenderDeviceID\" ,\"HKPFRN\":\"HKPFRN\" ,\
\"SourceType\":\"SourceType\" ,\"RecorderNo\":\"RecorderNo\"}";

	printf("the json data is [%lu][%s] \n\n", strlen(client_json_data), client_json_data);

	//然后需要构造特定的客户端数据 msg_type|dev_type|datalen|data sprintf 
	int msg_type = 2;
	int dev_type = 4;
	int data_len = strlen(client_json_data);
	char * client_data = NULL;
	int client_data_len = sizeof(int) *3 + data_len;
	client_data = (char *)malloc(client_data_len);
	memset(client_data, client_data_len, 0 );
	//这里应该在最后一位还有一个checksum得计算
	sprintf(client_data, "%d|%d|%d|%s", msg_type, dev_type, data_len, client_json_data);
	// sprintf(client_data, "%d|%d|%d|%s\0\0", msg_type, dev_type, data_len, client_json_data); //可以确保后面的逻辑
	printf("the client json data is [%lu][%s]\n\n", strlen(client_data), client_data);

	//如果要用网络进行发送，在末尾增加checksum, 需要注意前面字段得长度  用char数组和字符串存储得区别 可能有特殊字符 这里demo，简单假设
	//假设构造一个字符checksum 需要计算得
	// char check_sum = ']';
	char check_sum = vps_checkxor(client_data, strlen(client_data));
	client_data[strlen(client_data)] = check_sum;   //这里最好给紧跟着后面的字段赋值'\0'代表字符串的终结
	printf("the client json data is [%lu][%c][%s]\n\n", strlen(client_data), check_sum, client_data);
	if(client_data)
	{
		free(client_data);
		client_data = NULL;
	}
	
	return ;
}

struct client_recv_t
{
	int msg_type;
	int dev_type;
	int data_len;
	char data[0];
};

int check_recv_data_by_spilit(const char * data, int len, char **result, const char* delim);
//校验接收到的msg_type|dev_type|data_len|json_data checksum 校验数据内容，然后解析json打印相关字符
void check_client_data()
{
	//0：首先进行checksum校验
	//1：使用'|'进行切割，获取到各部分的长度
	//2：解析json数据，获取到相应的数据字段
	const char* src_data = "2|4|645|{\"DNIS\":\"dnis\" , \"ACDGroup\":\"ACDGroup\" ,\"TrunkNo\":\"TrunkNo\" ,\
\"ExtNo\":\"ExtNo\" ,\"CallerNo\":\"CallerNo\" ,\"CalledPartyNo\":\"CalledPartyNo\" , \"CallMark\":\"CallMark\" ,\
\"UniqueCallID\":\"UniqueCallID\" ,\"IncidentNo\":\"IncidentNo\" , \"StationOrDepot\":\"StationOrDepot\" ,\
\"OperatorID\":\"OperatorID\" ,\"WorkstationNo\":\"WorkstationNo\" , \"CallerVehicleID\":\"CallerVehicleID\" ,\
\"GSSI\":\"GSSI\" ,\"GSSI\":\"GSSI\" ,\"ResourceStatus\":\"ResourceStatus\" ,\"OicOrOfficerID\":\"OicOrOfficerID\" ,\
\"ISSI\":\"ISSI\" , \"CalledSSI\":\"CalledSSI\" ,\"CallType\":\"CallType\" ,\"FileLink\":\"FileLink\" , \
\"SenderDeviceID\":\"SenderDeviceID\" ,\"HKPFRN\":\"HKPFRN\" ,\"SourceType\":\"SourceType\" ,\
\"RecorderNo\":\"RecorderNo\"}q";
	
	char checksum = vps_checkxor(src_data, strlen(src_data)-1);
	printf("strlen(src_data)== %lu, %c \n\n", strlen(src_data), checksum);
	if(checksum != src_data[strlen(src_data)-1])
	{
		printf("check data error \n\n");
	}else
	{
		printf("check data success \n\n");
	}

	char * result_data_t = NULL;
	//使用|对数据进行切割 如果是网络数据 注意数据的长度 实际数据的处理应该已经丢掉checksum
	if(check_recv_data_by_spilit(src_data, strlen(src_data)-1, &result_data_t, "|") != 0)
	{
		printf("vps parse spilit error \n");
	}else
	{
		struct client_recv_t *result_data = (struct client_recv_t *)result_data_t;
		printf("\nstruct data is [%d][%d][%d][%s] \n", result_data->msg_type, result_data->dev_type, result_data->data_len, result_data->data);
		memset(result_data, sizeof(struct client_recv_t)+ (result_data->data_len+1), 0);
		// free(result_data);
		// result_data = NULL;
		if(result_data != NULL)
		{
			free(result_data);
			result_data = NULL;
			printf("free success \n");
		}
	}

}

//使用| 对接收数据进行解析并保存在结构中，去掉末尾一位校验
//这里不能直接传参  复制拷贝了 函数内部修改不生效
int check_recv_data_by_spilit(const char * data, int len, char **result, const char* delim)
{
	//直接根据'|'对字符串进行切割 根据切割后的个数进行校验
	char *src = strdup(data); //复制了一份数据 需要处理
	char * src_free = src; 

	//根据|分割后结构数据的个数，定义结构存储相关字符串地址位置
	//这里协商以前3个|为准，所以会得到四个地址
	char * delim_buff[4] = {0};
	char* token = NULL;  //切割后返回的字符指针
	int i = 0;			 //切割的个数
	for(token = strsep(&src, delim); token!=NULL && i<4; token=strsep(&src, delim))
	{
		delim_buff[i++] = token;
		printf("spilt data [%d:%lu:%s] \n", i, strlen(token), token);
	}

	if(i != 4)
	{
		printf("vps spilit data error \n");
		free(src_free);
		return -1;
	}

	int msg_type = (int)atoi(delim_buff[0]);
	int dev_type = (int)atoi(delim_buff[1]);
	int data_len = (int)atoi(delim_buff[2]);
	char * cli_data = delim_buff[3];
	printf("\nmsg_type:%d, dev_type:%d, data_len:%d:%lu:[%s] \n", msg_type, dev_type, data_len, strlen(cli_data), cli_data);

	//理解错了 这里不是对单独的data进行checksum
	// char check_sum = cli_data[strlen(cli_data)-1];
	// if(check_sum != vps_checkxor(cli_data, strlen(cli_data)-1))
	// {
	// 	printf("vps parse data check error[%c][%c] \n", vps_checkxor(cli_data, strlen(cli_data)-1), check_sum);
	// }else
	// {
	// 	printf("vps parse data check success \n ");
	// }
	int ret = 0;
	struct client_recv_t *result_t = NULL;
	result_t = (struct client_recv_t *)malloc(sizeof(struct client_recv_t) + data_len+1);
	if(result_t == NULL)
	{
		printf("malloc error \n");
		*result = NULL;
		ret = -1;
	}else
	{
		memset(result_t, sizeof(struct client_recv_t) + data_len+1, 0);
		result_t->msg_type = msg_type;
		result_t->dev_type = dev_type;
		result_t->data_len = data_len;
		memcpy(result_t->data, cli_data, data_len);
		*result = (char *)result_t;
	}

	memset(src_free, 0, len);
	free(src_free);
	src_free = NULL;

	return ret;

}